#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <pthread.h>
#include "log.hpp"
#include "threadPool.hpp"
#include "Task.hpp"
#include "Daemon.hpp"

extern Log lg;

enum
{
  USAGE_ERROR = 1,
  SOCKET_ERROR,
  BIND_ERROR,
  LISTEN_ERROR
};

const std::string defaultip = "0.0.0.0";
const int backlog = 10; // 不能设置太大

class Tcpserver;

class ThreadData
{
public:
  ThreadData(int sockfd, const std::string &clientip, const uint16_t &clientport, Tcpserver *tcpsvr)
      : _sockfd(sockfd), _clientip(clientip), _clientport(clientport), _tcpsvr(tcpsvr)
  {
  }

public:
  int _sockfd;
  std::string _clientip;
  uint16_t _clientport;
  Tcpserver *_tcpsvr;
};

class Tcpserver
{
public:
  Tcpserver(const uint16_t &port, const std::string &ip = defaultip) : _listensock(-1), _ip(ip), _port(port)
  {
  }

  void InitServer()
  {
    // 1. 创建tcp套接字
    _listensock = socket(AF_INET, SOCK_STREAM, 0);
    if (_listensock < 0)
    {
      lg(Fatal, "socket create error, errno: %d, errmsg: %s", errno, strerror(errno));
      exit(SOCKET_ERROR);
    }
    lg(Info, "socket create success, sockfd: %d, errmsg: %s", _listensock, strerror(errno));

    // 2. 绑定到操作系统
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(_port);
    inet_pton(AF_INET, _ip.c_str(), &local.sin_addr);

    socklen_t len = sizeof(local);

    if (bind(_listensock, (struct sockaddr *)&local, len) < 0)
    {
      lg(Fatal, "bind socket error, errno: %d, errmsg: %s", errno, strerror(errno));
      exit(BIND_ERROR);
    }
    lg(Info, "bind socket success, sockfd: %d, errmsg: %s", _listensock, strerror(errno));

    // 3. 监听
    if (listen(_listensock, backlog) < 0)
    {
      lg(Warning, "listen socket error, errno: %d, errmsg: %s", errno, strerror(errno));
      exit(LISTEN_ERROR);
    }
    lg(Info, "bind socket success, sockfd: %d, errmsg: %s", _listensock, strerror(errno));
  }

  // version --- 3 多线程的处理
  // static void *threadRoutine(void *args)
  // {
  //   pthread_detach(pthread_self());
  //   ThreadData *td = static_cast<ThreadData *>(args);
  //   td->_tcpsvr->service(td->_sockfd, td->_clientip, td->_clientport);
  // }

  void Start()
  {
    Daemon();
    lg(Info, "tcpserver is running.......");
    ThreadPool<Task>::GetIntance()->start();
    for (;;)
    {
      // 1. 接收链接
      struct sockaddr_in client;
      socklen_t len = sizeof(client);
      int sockfd = accept(_listensock, (struct sockaddr *)&client, &len);
      if (sockfd < 0)
      {
        lg(Warning, "accept error, errno: %d, errmsg: %s", errno, strerror(errno));
        continue;
      }
      lg(Info, "accpet success, sockfd: %d, errmsg: %s", sockfd, strerror(errno));
      // 2. 使用新链接进行通信
      uint16_t clientport = ntohs(client.sin_port);
      char clientip[32];
      inet_ntop(AF_INET, &client.sin_addr, clientip, sizeof(clientip));

      // version --- 1
      // service(sockfd, clientip, clientport);
      // close(sockfd);

      // version --- 2 // 父子进程
      // pid_t id = fork();
      // if (id == 0)
      // {
      //   // child
      //   close(_listensock);
      //   if (fork() > 0)
      //     exit(0);
      //   service(sockfd, clientip, clientport);
      // }
      // // parent
      // close(sockfd);
      // waitpid(id, nullptr, 0);

      // version --- 3 // 多线程, 直接将线程分离
      // pthread_t pid;
      // ThreadData *td = new ThreadData(sockfd, clientip, clientport, this);
      // pthread_create(&pid, nullptr, threadRoutine, td);

      // 4. 线程池
      Task t(sockfd, clientip, clientport);

      ThreadPool<Task>::GetIntance()->push(t);
    }
  }

  // void service(int sockfd, const std::string &clientip, const uint16_t &clientport)
  // {
  //   char buffer[4096];
  //   while (true)
  //   {
  //     ssize_t n = read(sockfd, buffer, sizeof(buffer));
  //     if (n > 0)
  //     {
  //       buffer[n] = 0;
  //       std::cout << "Client say# " << buffer << std::endl;

  //       std::string message = "tcpserver say@ ";
  //       message += buffer;
  //       write(sockfd, message.c_str(), message.size());
  //     }
  //     else if (n == 0)
  //     {
  //       lg(Info, "%s:%d, server close sockfd: %d", clientip.c_str(), clientport, sockfd);
  //       break;
  //     }
  //     else
  //     {
  //       lg(Error, "read Error..., errno: %d, errmsg: %s", errno, strerror(errno));
  //       break;
  //     }
  //   }

  //   close(sockfd);
  // }

  ~Tcpserver()
  {
    if (_listensock != -1)
      close(_listensock);
  }

private:
  int _listensock;
  std::string _ip;
  uint16_t _port;
};